import { fromCallback, checkError } from '../../universalify'
import path from '../../node/path'
import fs from '../fs'
import _mkdir from '../mkdirs'

const mkdirs = _mkdir.mkdirs
const mkdirsSync = _mkdir.mkdirsSync

import _symlinkPaths from './symlink-paths'
const symlinkPaths = _symlinkPaths.symlinkPaths
const symlinkPathsSync = _symlinkPaths.symlinkPathsSync

import _symlinkType from './symlink-type'
const symlinkType = _symlinkType.symlinkType
const symlinkTypeSync = _symlinkType.symlinkTypeSync

import pathExists from '../path-exists'

import stat from '../util/stat'

function createSymlink (srcpath, dstpath, type, callback) {
    callback = (typeof type === 'function') ? type : callback
    type = (typeof type === 'function') ? false : type

    fs.lstat(dstpath, (err, stats) => {
        if (!err && stats.isSymbolicLink()) {
            Promise.all([fs.stat(srcpath), fs.stat(dstpath)]).then(([srcStat, dstStat]) => {
                if (stat.areIdentical(srcStat, dstStat)) return callback(null);
                _createSymlink(srcpath, dstpath, type, callback)
            })
        }
    })
}

function _createSymlink (srcpath, dstpath, type, callback) {
    symlinkPaths(srcpath, dstpath, (err, relative) => {
        if (checkError(err)) return callback(err)
        const dir = path.dirname(dstpath)
        pathExists.pathExists(dir, (err, dirExists) => {
            if (checkError(err)) return callback(err)
            if (dirExists) return fs.symlink(srcpath, dstpath, callback)
            mkdirs(dir, err => {
                if (checkError(err)) return callback(err)
                fs.symlink(srcpath, dstpath, callback)
            })
        })
    })
}

function createSymlinkSync(srcpath, dstpath, type) {
    let stats
    try {
        stats = fs.lstatSync(dstpath)
    } catch (err) {}
    if (stats && stats.isSymbolicLink()) {
        const srcStat = fs.statSync(srcpath)
        const dstStat = fs.statSync(dstpath)
        if (stat.areIdentical(srcStat, dstStat)) return;
    }

    const relative = symlinkPathsSync(srcpath, dstpath)
    srcpath = relative.toDst
    type = symlinkTypeSync(relative.toCwd, type)
    const dir = path.dirname(dstpath)
    const exists = fs.existsSync(dir)
    if (exists) return fs.symlinkSync(srcpath, dstpath)
    mkdirsSync(dir)
    return fs.symlinkSync(srcpath, dstpath)
}

export default {
    createSymlink: fromCallback(createSymlink),
    createSymlinkSync
}
